async function sleep(ms = 1000): Promise<void> {
  await new Promise<void>((resolve): ReturnType<typeof setTimeout> => setTimeout((): void => resolve(), ms));
}

// 异步函数1
async function af(): Promise<void> {
  console.log("af start");
  await sleep(100);
  console.log("af return");
}

// 异步函数2
async function af2(): Promise<number> {
  console.log("af2 start");
  await sleep(100);
  console.log("af2 return");
  return 0;
}

// 异步函数3
async function af3(): Promise<void> {
  console.log("af3 start");
  await sleep(100);
  console.log("af3 return");
}

// 异步函数4
async function af4(): Promise<void> {
  console.log("af4 start");
  await sleep(100);
  console.log("af4 end");
}

// 同步函数，但是返回 Promise
function f(): Promise<void> {
  console.log("f start");
  // 得到 Promise 但是不求值，一个没有实际作用的 sleep
  sleep(100);
  console.log("f return");
  return new Promise<void>((resolve, reject): void => reject(-1));
}

// 同步函数，使用 node 的事件循环变为异步
function f2(): ReturnType<typeof process.nextTick> {
  console.log("f2 start");
  console.log("f2 return");
  // 回调是一个同步函数，但是放入下一个 tick 执行，因此变为异步，和注释此行上分的代码不在同一个 tick 执行
  return process.nextTick((): void => {
    console.log("f2 next tick start");
    console.log("f2 next tick return");
  });
}

// 同步函数，返回 Promise
function f3(): Promise<number> {
  console.log("f3 start");
  console.log("f3 return");
  return Promise.resolve(1024);
}

// 得到 Promise 并在求值后运行链式调用
(async function main(): Promise<void> {
  // 得到 Promise
  console.log("af get return value", af());
  // 得到 Promise 并求值
  console.log("af2 get return value", await af2());
  // 得到 Promise
  af3();
  // 得到 Promise 并在求值后运行链式调用
  af4()
    .then((): void => console.log("af4 then"))
    .catch((): void => console.log("af4 catch"))
    .finally((): void => console.log("af4 finally"));
  // 得到 Promise
  f().catch((e) => console.log("f catch", e));
  // 得到返回值
  console.log("f2 get return value", f2());
  // 得到 Promise 并在求值时运行链式调用处理异常
  f3()
    .then((c): number => {
      throw `f3 then throw error message with ${c}`;
      return c;
    })
    .then((c): void => console.log(`f3 then get value ${c}`))
    .catch((e): void => console.log("f3 catch get", e));

  await sleep();
})().then(() => process.exit(0));

export {};
